/*
Pyxis 2.0
Copyright 2010-2011 Thomas W. Holtquist

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

using System;
using System.Collections;
using System.Ext.Xml;
using System.IO;
using System.Text;
using System.Xml;

using Microsoft.SPOT;

namespace Skewworks.Pyxis.Kernel
{
    public class FileManager : MarshalByRefObject
    {

        #region Structures

        [Serializable]
        public struct FileAssociation
        {
            public string Extension;
            public Bitmap Icon;
            public string LaunchPath;
            public string IconPath;
        }

        #endregion

        #region Variables

        private PyxisAPI API;
        private Hashtable _assoc;
        private bool _bLoaded = false;

        #endregion

        #region Constructor

        internal FileManager(PyxisAPI api)
        {
            API = api;
            LoadAssociations();
        }

        #endregion

        #region Properties

        public bool Loaded
        {
            get { return _bLoaded; }
        }

        #endregion

        #region Public Methods

        public bool AssociateType(string ext, string target, string icon)
        {

            // Make sure we have a drive selected
            if (API.MyDrives.RootDirectory == "\\")
                return false;

            // Prep the structure
            FileAssociation FA = new FileAssociation();
            FA.Extension = ext.ToLower();
            FA.IconPath = icon;
            FA.Icon = IcoFromString(FA.IconPath);
            FA.LaunchPath = target;

            // Add the association
            if (_assoc[FA.Extension] != null)
                _assoc.Remove(FA.Extension);

            _assoc.Add(FA.Extension, FA);

            return true;
        }

        public Bitmap GetAssociatedIcon(string ext)
        {
            if (_assoc == null) return Resources.GetBitmap(Resources.BitmapResources.file);
            if (_assoc[ext.ToLower()] == null) return Resources.GetBitmap(Resources.BitmapResources.file);
            FileAssociation FA = (FileAssociation)_assoc[ext.ToLower()];
            return FA.Icon;
        }

        public string GetAssociatedApplication(string ext)
        {
            if (_assoc[ext.ToLower()] == null) return string.Empty;
            FileAssociation FA = (FileAssociation)_assoc[ext.ToLower()];
            return FA.LaunchPath;
        }

        /// <summary>
        /// Loads file associations from primary drive
        /// </summary>
        public void LoadAssociations()
        {
            byte[] b;
            string sPath = API.MyDrives.RootDirectory + "pyxis\\system\\assoc.db";
            FileStream fs;
            FileAssociation FA;

            // No primary drive; no point continuing
            if (API.MyDrives.RootDirectory == "\\") return;

            if (!File.Exists(sPath))
            {
                // Create associations
                fs = new FileStream(sPath, FileMode.Create, FileAccess.Write);
                b = Encoding.UTF8.GetBytes(Resources.GetString(Resources.StringResources.DefaultAssociations));
                fs.Write(b, 0, b.Length);
                fs.Close();
                API.MyDrives.FlushFileSystems();
            }
            else
            {
                // Read associations
                fs = new FileStream(sPath, FileMode.Open, FileAccess.Read);
                b = new byte[(int)fs.Length];
                fs.Read(b, 0, b.Length);
                fs.Close();
            }

            // Reset the Table
            _assoc = new Hashtable();

            // Load the Data
            XmlReaderSettings xmlReaderSettings = new XmlReaderSettings();
            xmlReaderSettings.IgnoreComments = true;
            xmlReaderSettings.IgnoreProcessingInstructions = true;
            xmlReaderSettings.IgnoreWhitespace = true;
            MemoryStream stream = new MemoryStream(b);
            XmlReader reader = XmlReader.Create(stream, xmlReaderSettings);

            if (!reader.ReadToDescendant("associations"))
            {
                API.Prompt("File associations could not be loaded!\nFile may be corrupt.\nTry deleting the file and rebooting.", PyxisAPI.Product, PromptType.OKOnly);
                return;
            }

            while (reader.Read() && !(reader.NodeType == XmlNodeType.EndElement && reader.Name == "associations"))
            {
                try
                {
                    FA = new FileAssociation();
                    FA.Extension = reader.GetAttribute("ext").ToLower();
                    FA.IconPath = reader.GetAttribute("ico");
                    FA.Icon = IcoFromString(FA.IconPath);
                    FA.LaunchPath = reader.GetAttribute("path");
                    _assoc.Add(FA.Extension, FA);
                }
                catch (Exception e)
                {
                    Debug.Print("Error loading association: " + e.Message);
                }
            }

            _bLoaded = true;
        }

        /// <summary>
        /// Ensures the directory ends with a '\' character
        /// </summary>
        /// <param name="Path"></param>
        /// <returns></returns>
        public static string NormalizeDirectory(string Path)
        {
            if (Path.Substring(Path.Length - 1) != "\\") return Path + "\\";
            return Path;
        }

        public bool SaveAssociations()
        {
            byte[] b;
            string sPath = API.MyDrives.RootDirectory + "pyxis\\system\\assoc.db";
            FileAssociation FA;

            // Make sure we can save
            if (_assoc == null || API.MyDrives.RootDirectory == "\\")
                return false;

            // Delete existing file
            if (File.Exists(sPath))
                File.Delete(sPath);

            // Write the file
            FileStream iFile = new FileStream(sPath, FileMode.OpenOrCreate, FileAccess.Write);

            // Header
            b = UTF8Encoding.UTF8.GetBytes("<?xml version=\"1.0\" encoding=\"utf-8\" ?>\r\n<associations>\r\n");
            iFile.Write(b, 0, b.Length);

            // Associations
            foreach (DictionaryEntry item in _assoc) 
            {
                FA = (FileAssociation)item.Value;
                b = UTF8Encoding.UTF8.GetBytes("<assoc ext=\"" + FA.Extension + "\" icon=\"" + FA.IconPath + "\" path=\"" + FA.LaunchPath + "\" />\r\n");
                iFile.Write(b, 0, b.Length);
            }

            // Footer
            b = UTF8Encoding.UTF8.GetBytes("</associations>");
            iFile.Write(b, 0, b.Length);

            // Close file
            iFile.Close();

            return true;
        }

        #endregion

        #region Internal Methods

        internal static string GetFile(string file)
        {
            for (int i = 0; i < 9999; i++)
            {
                if (!File.Exists(file + i + ".lnk"))
                    return file + i;
            }

            // we give up, return original file and error out
            return file;
        }

        #endregion

        #region Private Methods

        private Bitmap IcoFromString(string ico)
        {
            switch (ico)
            {
                case "-1":
                    return Resources.GetBitmap(Resources.BitmapResources.pxe);
                case "-2":
                    return Resources.GetBitmap(Resources.BitmapResources.bmp);
                case "-3":
                    return Resources.GetBitmap(Resources.BitmapResources.jpg);
                case "-4":
                    return Resources.GetBitmap(Resources.BitmapResources.gif);
                case "-5":
                    return Resources.GetBitmap(Resources.BitmapResources.installer);
                default:
                    if (File.Exists(ico))
                    {
                        Bitmap bmp = PyxisAPI.ImageFromBytes(File.ReadAllBytes(ico));
                        if (bmp == null) return Resources.GetBitmap(Resources.BitmapResources.file);
                        return bmp;
                    }
                    return Resources.GetBitmap(Resources.BitmapResources.file);
            }
        }

        #endregion

    }
}
